package com.zzyl.nursing.service.impl;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.common.utils.StringUtils;
import com.zzyl.nursing.config.WebSocketServer;
import com.zzyl.nursing.domain.AlertData;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IAlertDataService;
import com.zzyl.nursing.vo.AlertNotifyVo;
import com.zzyl.system.mapper.SysUserRoleMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.AlertRuleMapper;
import com.zzyl.nursing.domain.AlertRule;
import com.zzyl.nursing.service.IAlertRuleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import javax.print.attribute.standard.NumberUp;

/**
 * 报警规则Service业务层处理
 *
 * @author alexis
 * @date 2025-11-13
 */
@Service
@Slf4j
public class AlertRuleServiceImpl extends ServiceImpl<AlertRuleMapper, AlertRule> implements IAlertRuleService {
    @Autowired
    private AlertRuleMapper alertRuleMapper;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    IAlertDataService alertDataService;

    @Value("${alert.deviceMaintainerRole}")
    private String deviceMaintainerRole;

    @Value("${alert.deviceMaintainerRole}")
    private String managerRole;

    /**
     * 查询报警规则
     *
     * @param id 报警规则主键
     * @return 报警规则
     */
    @Override
    public AlertRule selectAlertRuleById(Long id) {
        return alertRuleMapper.selectById(id);
    }

    /**
     * 查询报警规则列表
     *
     * @param alertRule 报警规则
     * @return 报警规则
     */
    @Override
    public List<AlertRule> selectAlertRuleList(AlertRule alertRule) {
        return alertRuleMapper.selectAlertRuleList(alertRule);
    }

    /**
     * 新增报警规则
     *
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int insertAlertRule(AlertRule alertRule) {
        return alertRuleMapper.insert(alertRule);
    }

    /**
     * 修改报警规则
     *
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int updateAlertRule(AlertRule alertRule) {
        return alertRuleMapper.updateById(alertRule);
    }

    /**
     * 批量删除报警规则
     *
     * @param ids 需要删除的报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleByIds(Long[] ids) {
        return alertRuleMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除报警规则信息
     *
     * @param id 报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleById(Long id) {
        return alertRuleMapper.deleteById(id);
    }

    @Override
    public void alertFilter() {
        LambdaQueryWrapper<AlertRule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AlertRule::getStatus, 1);
        long count = count(wrapper);
        if (count > 0) {
            return;
        }
        List<Object> vaules = redisTemplate.opsForHash().values(CacheConstants.IOT_DEVICE_LAST_DATA);
        if (CollUtil.isEmpty(vaules)) {
            return;
        }
        ArrayList<DeviceData> list = new ArrayList<>();
        vaules.forEach(value -> {
            List<DeviceData> dataList = JSONUtil.toList(value.toString(), DeviceData.class);
            list.addAll(dataList);
        });
        list.forEach(d -> alertDataFilter(d));

    }

    private void alertDataFilter(DeviceData data) {
        LocalDateTime time = data.getAlarmTime();
        long between = LocalDateTimeUtil.between(time, LocalDateTime.now(), ChronoUnit.SECONDS);
        if (between > 60) {
            return;
        }
        LambdaQueryWrapper<AlertRule> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AlertRule::getProductKey, data.getProductKey())
                .eq(AlertRule::getFunctionId, data.getFunctionId())
                .eq(AlertRule::getIotId, 1)
                .eq(AlertRule::getStatus, 1);
        List<AlertRule> alertRules = list(wrapper);
        LambdaQueryWrapper<AlertRule> wrapper1 = new LambdaQueryWrapper<>();
        wrapper1.eq(AlertRule::getProductKey, data.getProductKey())
                .eq(AlertRule::getFunctionId, data.getFunctionId())
                .eq(AlertRule::getIotId, 0)
                .eq(AlertRule::getStatus, 1);
        List<AlertRule> alertRules1 = list(wrapper1);

        Collection<AlertRule> allRules = CollUtil.addAll(alertRules, alertRules1);
        if (CollUtil.isEmpty(allRules)) {
            return;
        }
        alertRules.forEach(a -> deviceAlertHandler(a, data));

    }

    private void deviceAlertHandler(AlertRule alertRule, DeviceData deviceData) {
        String[] split = alertRule.getAlertEffectivePeriod().split("~");
        LocalTime start = LocalTime.parse(split[0]);
        LocalTime end = LocalTime.parse(split[1]);
        LocalTime time = deviceData.getAlarmTime().toLocalTime();
        if (time.isBefore(start) || time.isAfter(end)) {
            return;
        }
        String iotId = deviceData.getIotId();
        String s = CacheConstants.ALERT_TRIGGER_COUNT_PREFIX + iotId + ":" + deviceData.getFunctionId()
                + ":" + alertRule.getId();

        int compare = NumberUtil.compare(Double.valueOf(deviceData.getDataValue()), alertRule.getValue());
        if (alertRule.getOperator().equals(">=") && compare >= 0
                || alertRule.getOperator().equals("<") && compare < 0) {
            log.info("当前上报的数据符合条件");
        } else {
            redisTemplate.delete(s);
            return;
        }
        //异常的数据会走到这里
        //判断是否在沉默周期内
        String silentKey = CacheConstants.ALERT_SILENT_PREFIX + iotId + ":" + deviceData.getFunctionId() + ":" + alertRule.getId();
        String silentData = redisTemplate.opsForValue().get(silentKey);


        if (StringUtils.isNotEmpty(silentData)) {
            return;
        }
        //持续周期的逻辑
        String aggData = redisTemplate.opsForValue().get(silentKey);
        int count = StringUtils.isEmpty(aggData) ? 1 : Integer.parseInt(aggData) + 1;
        //如果count与持续周期的值相等，则触发报警
        if (ObjectUtil.notEqual(count, alertRule.getDuration())) {
            //不相等
            redisTemplate.opsForValue().set(s, count + "");
            return;
        }
        //删除redis的报警数据
        redisTemplate.delete(s);
        //存储数据到沉默周期，设置一个过期时间，规则中的沉默周期
        redisTemplate.opsForValue().set(silentKey, "1", alertRule.getAlertSilentPeriod(), TimeUnit.MINUTES);

        List<Long> userIds = new ArrayList<>();
        if (alertRule.getAlertDataType().equals(0)) {
            userIds = deviceMapper.selectNursingIdsByIotIdWithElder(deviceData.getIotId());
        } else if (deviceData.getLocationType().equals(1) && deviceData.getPhysicalLocationType().equals(2)) {
            userIds = deviceMapper.selectNursingIdsByIotIdWithBed(deviceData.getIotId());
        } else {
            userIds = sysUserRoleMapper.selectUserIdByRoleName(deviceMaintainerRole);
        }

        List<Long> managerIds = sysUserRoleMapper.selectUserIdByRoleName(managerRole);
        Collection<Long> all = CollUtil.addAll(userIds, managerIds);
        all = CollUtil.distinct(all);
        // 批量保存异常数据
        List<AlertData> alertDataList = insertAlertData(all, alertRule, deviceData);

        // websocket推送消息
        websocketNotity(alertDataList.get(0), alertRule, all);

    }

    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * websocket推送消息
     *
     * @param alertData
     * @param rule
     * @param allUserIds
     */
    private void websocketNotity(AlertData alertData, AlertRule rule, Collection<Long> allUserIds) {

        // 属性拷贝
        AlertNotifyVo alertNotifyVo = BeanUtil.toBean(alertData, AlertNotifyVo.class);
        alertNotifyVo.setFunctionName(rule.getFunctionName());
        alertNotifyVo.setAlertDataType(rule.getAlertDataType());
        alertNotifyVo.setNotifyType(1);
        // 向指定的人推送消息
        webSocketServer.sendMessageToConsumer(alertNotifyVo, allUserIds);

    }

    private List<AlertData> insertAlertData(Collection<Long> all, AlertRule alertRule, DeviceData deviceData) {
        AlertData alertData = BeanUtil.toBean(deviceData, AlertData.class);
        String format = CharSequenceUtil.format("{} {} {},持续{}个周期"
                , deviceData.getFunctionId(), alertRule.getOperator(), alertRule.getValue(),
                alertRule.getDuration());

        alertData.setAlertReason(format);
        alertData.setStatus(0);
        alertData.setType(alertRule.getAlertDataType());
        alertData.setAlertRuleId(alertRule.getId());

        List<AlertData> collect = all.stream().map(userId -> {
            AlertData alertData1 = BeanUtil.toBean(alertData, AlertData.class);
            alertData1.setUserId(userId);
            alertData1.setUserId(null);
            alertData1.setId(null);
            return alertData1;
        }).collect(Collectors.toList());
        alertDataService.saveBatch(collect);
        return collect;
    }
}
